package zdream.pmfield.test.stage.battle;

import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicBoolean;

import zdream.pmfield.core.Result;
import zdream.pmfield.data.foe.Foe;
import zdream.pmfield.data.foe.MoveTemplate;
import zdream.pmfield.stage.StageBuilderForTest;
import zdream.pmfield.stage.StageWrapper;
import zdream.pmfield.stage.action.AttackAction;
import zdream.pmfield.stage.message.ActionRequestMessage;
import zdream.pmfield.stage.message.ActionRequestReply;
import zdream.pmfield.stage.message.FoeArriveMessage;
import zdream.pmfield.stage.message.FoeLeaveMessage;
import zdream.pmfield.stage.object.FoeActor;
import zdream.pmfield.stage.object.Seat;
import zdream.pmfield.storage.FoeTemplateStorage;

import static org.junit.Assert.*;

/**
 * @author Zdream
 * @date 2023-11-30
 * @since 0.0.1
 */
public class MoveToCase {
	FoeTemplateStorage storage;

	@Before
	public void before() {
		storage = new FoeTemplateStorage();
		storage.load();
	}

	@Test
	public void testNormalBattle() {
		MoveTemplate move1 = storage.findMoveById(1, 1);

		Foe foe1 = Foe.builder(storage.findFoeById(4))
				.withLevel(20)
				.withMove(move1)
				.build();
		Foe foe2 = Foe.builder(storage.findFoeById(1))
				.withLevel(20)
				.withMove(move1)
				.build();

		final StageWrapper wrapper = StageBuilderForTest.builder()
				.putFoeToOneSide(foe1)
				.putFoeToAnotherSide(foe2)
				.withStorage(storage)
				.buildWrapper();
		AtomicBoolean checked = new AtomicBoolean(false);
		AtomicBoolean leave = new AtomicBoolean(false), arrive = new AtomicBoolean(false);
		Seat[] seats = new Seat[2];
		FoeActor[] chosen = new FoeActor[1];

		wrapper.printBeforeHandleMessage();
		wrapper.onMessage(ActionRequestMessage.class, request -> {
			if (leave.get() && arrive.get()) {
				assertEquals(chosen[0].seat, seats[1]);
				checked.set(true);
				return;
			}

			final ActionRequestReply replyTemplate = request.createReplyTemplate();
			AttackAction action = replyTemplate.createAttackAction();

			if (action.foe.movePoint > 0) {
				action.move = action.foe.findMoveToMove();

				final Seat seat = action.foe.seat;
				if (seat.x < 0) {
					action.targetSeat = seat.right;
				} else {
					action.targetSeat = seat.left;
				}
			} else {
				action.move = action.foe.findSkipTurnMove();
				action.targetFoe = action.foe;
			}

			seats[0] = action.foe.seat;
			seats[1] = action.targetSeat;
			assertNotEquals(seats[0], seats[1]);
			chosen[0] = action.foe;

			replyTemplate.action = action;
			final Result result = request.commit(replyTemplate);
			assertTrue(result.errorMessage, result.success);
		});
		wrapper.onMessage(FoeLeaveMessage.class, message -> {
			assertFalse(arrive.get());
			assertEquals(message.foe, chosen[0].foe);
			assertEquals(message.seat, seats[0]);
			assertEquals(message.reason, FoeLeaveMessage.DepartureReason.MOVEMENT);
			leave.set(true);
		});
		wrapper.onMessage(FoeArriveMessage.class, message -> {
			assertEquals(message.foe, chosen[0]);
			assertEquals(message.seat, seats[1]);
			arrive.set(true);
		});

		wrapper.runUntil(stage -> checked.get());
	}
}
